package com.ruibang.glass.material.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.CommonErrorCode;
import com.ruibang.glass.common.constants.Constants;
import com.ruibang.glass.common.domain.camunda.BpmProcessInstanceCreate;
import com.ruibang.glass.frequencycontrol.annotation.RedissonLock;
import com.ruibang.glass.material.constant.MaterialErrorCode;
import com.ruibang.glass.material.constant.MaterialStatusCode;
import com.ruibang.glass.material.constant.MaterialWareHouseCode;
import com.ruibang.glass.material.domain.req.ApproveProcessReq;
import com.ruibang.glass.material.domain.req.MaterialALLInventoryManagementReq;
import com.ruibang.glass.material.domain.req.ycl.MaterialInventoryReq;
import com.ruibang.glass.material.dto.MaterialALLInventoryManagementDTO;
import com.ruibang.glass.material.entity.*;
import com.ruibang.glass.material.mapper.GMaterialALLInventoryManagementMapper;
import com.ruibang.glass.material.mapper.GMaterialALLOutboundManagementMapper;
import com.ruibang.glass.material.mapper.MaterialCheckItemMapper;
import com.ruibang.glass.material.service.GMaterialALLInventoryManagementService;
import com.ruibang.glass.material.service.MaterialLineSideWarehouseLocationService;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ruibang.glass.common.constants.RedisKey.MATERIAL_IN_WAREHOUSE_NUMBER;

/**
 * <p>
 * 原材料库存管理表 服务实现类
 * </p>
 *
 * @author mameng
 * @since 2024-04-01
 */
@Service
public class GMaterialALLInventoryManagementServiceImpl extends ServiceImpl<GMaterialALLInventoryManagementMapper, MaterialALLInventoryManagement> implements GMaterialALLInventoryManagementService {

    @Autowired
    private MaterialLineSideWarehouseLocationService materialLineSideWarehouseLocationService;

    @Autowired
    private MaterialCheckItemMapper materialCheckItemMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private GMaterialALLOutboundManagementMapper materialALLOutboundManagementMapper;

    private final String UPDATE_FROZEN_QUANTITY = "update_frozen_quantity";

    /**
     * 原材料库存管理表 服务实现类
     *
     * @param materialInventoryReq
     * @return
     */
    @Override
    public IPage<MaterialALLInventoryManagement> getPage(MaterialInventoryReq materialInventoryReq) {
        LambdaQueryWrapper<MaterialALLInventoryManagement> queryWrapper = Wrappers.<MaterialALLInventoryManagement>lambdaQuery();
        if (StringUtils.isNotBlank(materialInventoryReq.getMaterialCode())) {
            queryWrapper.like(MaterialALLInventoryManagement::getMaterialCode, materialInventoryReq.getMaterialCode());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getMaterialName())) {
            queryWrapper.like(MaterialALLInventoryManagement::getMaterialName, materialInventoryReq.getMaterialName());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getStorageLocation())) {
            queryWrapper.like(MaterialALLInventoryManagement::getStorageLocation, materialInventoryReq.getStorageLocation());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getStorageLocationId())) {
            queryWrapper.like(MaterialALLInventoryManagement::getStorageLocation, materialInventoryReq.getStorageLocationId());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getGrade())) {
            queryWrapper.like(MaterialALLInventoryManagement::getModelGrade, materialInventoryReq.getGrade());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getSpecification())) {
            queryWrapper.like(MaterialALLInventoryManagement::getSpecification, materialInventoryReq.getSpecification());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getSupplier())) {
            queryWrapper.like(MaterialALLInventoryManagement::getSupplier, materialInventoryReq.getSupplier());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getBatchNumber())) {
            queryWrapper.like(MaterialALLInventoryManagement::getBatchNumber, materialInventoryReq.getBatchNumber());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getWarehouseCode())) {
            queryWrapper.eq(MaterialALLInventoryManagement::getWareHouseCode, materialInventoryReq.getWarehouseCode());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getWarehouseName())) {
            queryWrapper.like(MaterialALLInventoryManagement::getWareHouseName, materialInventoryReq.getWarehouseName());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getATypeShelf())) {
            queryWrapper.like(MaterialALLInventoryManagement::getATypeShelf, materialInventoryReq.getATypeShelf());
        }

        if (StringUtils.isNotBlank(materialInventoryReq.getBarcodeNumber())) {
            queryWrapper.like(MaterialALLInventoryManagement::getBarcodeNumber, materialInventoryReq.getBarcodeNumber());
        }
        queryWrapper.ge(MaterialALLInventoryManagement::getStockQuantity, Constants.ONE_INT);
        Page<MaterialALLInventoryManagement> materialWarehouseInfoPage = baseMapper.selectPage(new Page<>(materialInventoryReq.getPageNo(), materialInventoryReq.getPageSize()),
                queryWrapper.orderByDesc(MaterialALLInventoryManagement::getCreateTime)
        );

        //计算可用数量
        //按照模块区分 查询冻结数量
        Map<String, String> materialWarehouseInfoMap = new HashMap<>();
        List<MaterialLineSideWarehouseLocation> materialLineSideWarehouseLocations = materialLineSideWarehouseLocationService.
                list(Wrappers.<MaterialLineSideWarehouseLocation>lambdaQuery().select(MaterialLineSideWarehouseLocation::getId, MaterialLineSideWarehouseLocation::getLocationName));


        for (MaterialLineSideWarehouseLocation materialLineSideWarehouseLocation : materialLineSideWarehouseLocations) {
            materialWarehouseInfoMap.put(materialLineSideWarehouseLocation.getId(), materialLineSideWarehouseLocation.getLocationName());
        }
        List<MaterialALLOutboundManagement> materialALLOutboundManagements = materialALLOutboundManagementMapper.selectList(Wrappers.<MaterialALLOutboundManagement>lambdaQuery().select(MaterialALLOutboundManagement::getId).eq(MaterialALLOutboundManagement::getWarehouseCode, materialInventoryReq.getWarehouseCode()));
        List<String> collect = materialALLOutboundManagements.stream().map(MaterialALLOutboundManagement::getId).collect(Collectors.toList());
        if (materialWarehouseInfoPage.getRecords() != null && materialWarehouseInfoMap != null) {
            for (MaterialALLInventoryManagement materialLineSideWarehouseLocation : materialWarehouseInfoPage.getRecords()) {
                //获取供应商
                if (StringUtils.isNotEmpty(materialLineSideWarehouseLocation.getSupplier())) {
                    String supplierName = baseMapper.getSupplierName(materialLineSideWarehouseLocation.getSupplier());
                    materialLineSideWarehouseLocation.setSupplier(supplierName);
                }
                if (materialLineSideWarehouseLocation.getScrapQuantity() == null) {
                    materialLineSideWarehouseLocation.setScrapQuantity(BigDecimal.ZERO);
                }
                if (materialLineSideWarehouseLocation.getFrozenQuantity() == null) {
                    materialLineSideWarehouseLocation.setFrozenQuantity(BigDecimal.ZERO);
                }
                if (materialLineSideWarehouseLocation.getAvailableQuantity() == null) {
                    materialLineSideWarehouseLocation.setAvailableQuantity(BigDecimal.valueOf(materialLineSideWarehouseLocation.getStockQuantity()));
                }
//                BigDecimal djQuality = BigDecimal.ZERO;
//                if (materialInventoryReq.getWarehouseCode().equals(MaterialWareHouseCode.YCLK_CK.getMsg())) {
//                    djQuality = baseMapper.getDJYClQuality(materialLineSideWarehouseLocation.getMaterialCode(), materialLineSideWarehouseLocation.getBatchNumber(), materialLineSideWarehouseLocation.getBarcodeNumber(), collect);
//                } else if (materialInventoryReq.getWarehouseCode().equals(MaterialWareHouseCode.CPK_CK.getMsg())) {
//                    djQuality=  baseMapper.getCPDJYClQuality(materialLineSideWarehouseLocation.getATypeShelf());
//                } else if (materialInventoryReq.getWarehouseCode().equals(MaterialWareHouseCode.BCPK_CK.getMsg())) {
//                    djQuality=  baseMapper.getBCPDJYClQuality(materialLineSideWarehouseLocation.getATypeShelf());
//                } else {
//                    djQuality = baseMapper.getDJQuality(materialLineSideWarehouseLocation.getMaterialName(), materialLineSideWarehouseLocation.getMaterialCode(), collect);
//                }
//                BigDecimal dbdjQuality = baseMapper.getDBDJQuality(materialLineSideWarehouseLocation.getMaterialName(), materialLineSideWarehouseLocation.getMaterialCode());
//                BigDecimal cotnTotal = BigDecimal.ZERO;
//                if (djQuality != null) {
//                    cotnTotal = cotnTotal.add(djQuality);
//                }
//                if (dbdjQuality != null) {
//                    cotnTotal = cotnTotal.add(dbdjQuality);
//                }
//                if (materialLineSideWarehouseLocation.getStockQuantity() != null) {
//                    BigDecimal count = BigDecimal.valueOf(materialLineSideWarehouseLocation.getStockQuantity()).subtract(cotnTotal);
//                    materialLineSideWarehouseLocation.setAvailableQuantity(count);
//                    materialLineSideWarehouseLocation.setFrozenQuantity(cotnTotal);
//                    materialLineSideWarehouseLocation.setScrapQuantity(BigDecimal.ZERO);
//                } else {
//                    materialLineSideWarehouseLocation.setAvailableQuantity(BigDecimal.ZERO);
//                    materialLineSideWarehouseLocation.setFrozenQuantity(cotnTotal);
//                    materialLineSideWarehouseLocation.setScrapQuantity(BigDecimal.ZERO);
//                }
                if (materialWarehouseInfoMap.get(materialLineSideWarehouseLocation.getStorageLocation()) != null) {
                    materialLineSideWarehouseLocation.setStorageLocation(materialWarehouseInfoMap.get(materialLineSideWarehouseLocation.getStorageLocation()));
                }
            }

        }
        return materialWarehouseInfoPage;
    }


    @Override
    public IPage<MaterialALLInventoryManagement> getCheckPageList(MaterialInventoryReq materialInventoryReq) {
        LambdaQueryWrapper<MaterialALLInventoryManagement> queryWrapper = Wrappers.<MaterialALLInventoryManagement>lambdaQuery();
        if (StringUtils.isNotBlank(materialInventoryReq.getMaterialCode())) {
            queryWrapper.like(MaterialALLInventoryManagement::getMaterialCode, materialInventoryReq.getMaterialCode());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getMaterialName())) {
            queryWrapper.like(MaterialALLInventoryManagement::getMaterialName, materialInventoryReq.getMaterialName());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getStorageLocation())) {
            queryWrapper.like(MaterialALLInventoryManagement::getStorageLocation, materialInventoryReq.getStorageLocation());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getSupplier())) {
            queryWrapper.like(MaterialALLInventoryManagement::getSupplier, materialInventoryReq.getSupplier());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getBatchNumber())) {
            queryWrapper.like(MaterialALLInventoryManagement::getBatchNumber, materialInventoryReq.getBatchNumber());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getWarehouseCode())) {
            queryWrapper.like(MaterialALLInventoryManagement::getWareHouseCode, materialInventoryReq.getWarehouseCode());
        }
        if (StringUtils.isNotBlank(materialInventoryReq.getWarehouseName())) {
            queryWrapper.like(MaterialALLInventoryManagement::getWareHouseName, materialInventoryReq.getWarehouseName());
        }

        if (StringUtils.isNotBlank(materialInventoryReq.getBarcodeNumber())) {
            queryWrapper.like(MaterialALLInventoryManagement::getBarcodeNumber, materialInventoryReq.getBarcodeNumber());
        }
        queryWrapper.ge(MaterialALLInventoryManagement::getStockQuantity, Constants.ONE_STR);
        queryWrapper.orderByDesc(MaterialALLInventoryManagement::getMaterialCode).orderByDesc(MaterialALLInventoryManagement::getMaterialName).orderByDesc(MaterialALLInventoryManagement::getBatchNumber);
        Page<MaterialALLInventoryManagement> materialWarehouseInfoPage = baseMapper.selectPage(new Page<>(materialInventoryReq.getPageNo(), materialInventoryReq.getPageSize()),
                queryWrapper.orderByDesc(MaterialALLInventoryManagement::getCreateTime)
        );


        if (materialWarehouseInfoPage.getRecords() != null) {
            for (MaterialALLInventoryManagement materialLineSideWarehouseLocation : materialWarehouseInfoPage.getRecords()) {
                MaterialCheckItem materialCheckItem = materialCheckItemMapper.selectOne(Wrappers.<MaterialCheckItem>lambdaQuery()
                        .eq(MaterialCheckItem::getAllId, materialLineSideWarehouseLocation.getId())
                        .eq(MaterialCheckItem::getCheckId, materialInventoryReq.getCheckId())
                        .last("limit 1")
                );
                if (materialCheckItem != null) {
                    materialLineSideWarehouseLocation.setCheckQuality(materialCheckItem.getCheckQuality());
                    materialLineSideWarehouseLocation.setRemark(materialCheckItem.getRemark());
                }
            }
        }

        return materialWarehouseInfoPage;
    }

    @Override
    public Map<String, Map<String, List<MaterialALLInventoryManagementDTO>>> getMaterialALLInventoryManagementDTO() {
        List<MaterialALLInventoryManagementDTO> yclMaterialList = baseMapper.getMaterialALLInventoryManagementDTO();
        if (CollectionUtils.isNotEmpty(yclMaterialList)) {
            Map<String, Map<String, List<MaterialALLInventoryManagementDTO>>> yclMaterialMap = yclMaterialList.stream().collect(Collectors.groupingBy(MaterialALLInventoryManagementDTO::getMaterialName
                    , Collectors.groupingBy(MaterialALLInventoryManagementDTO::getBatchNumber)));
            return yclMaterialMap;
        }
        return Collections.emptyMap();
    }

    @Override
    public List<MaterialALLInventoryManagementDTO> getYclLocationMaterial(String barcodeNumber, String batchNumber) {
        if (StringUtils.isNotBlank(batchNumber) && StringUtils.isNotBlank(barcodeNumber)) {
            return baseMapper.getYclLocationMaterial(barcodeNumber, batchNumber);
        }
        return Collections.emptyList();
    }

    @Override
    public List<MaterialALLInventoryManagementDTO> getYclMaterialList() {
        List<MaterialALLInventoryManagementDTO> yclMaterialList = baseMapper.getMaterialALLInventoryManagementDTO();
        if (CollectionUtils.isNotEmpty(yclMaterialList)) {
            return yclMaterialList;
        }
        return Collections.emptyList();
    }

    @Override
    public MaterialALLInventoryManagement getMaterialALLInventoryManagementByPcNumber(String pcNumber) {
        return baseMapper.getMaterialALLInventoryManagementByPcNumber(pcNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = UPDATE_FROZEN_QUANTITY, prefixKey = "lock_", waitTime = 5)
    public void removeFrozenQuantity(List<MaterialALLInventoryManagementReq> materialALLInventoryManagementReqList) {
        for (MaterialALLInventoryManagementReq materialALLInventoryManagementReq : materialALLInventoryManagementReqList) {
            MaterialALLInventoryManagement materialALLInventoryManagement = baseMapper.selectOne(Wrappers.<MaterialALLInventoryManagement>lambdaQuery()
                    .eq(MaterialALLInventoryManagement::getWareHouseCode, MaterialWareHouseCode.YCLK_CK.getMsg())
                    .eq(MaterialALLInventoryManagement::getBatchNumber, materialALLInventoryManagementReq.getBatchNumber())
                    .eq(MaterialALLInventoryManagement::getBarcodeNumber, materialALLInventoryManagementReq.getBarcodeNumber())
                    .eq(MaterialALLInventoryManagement::getStorageLocation, materialALLInventoryManagementReq.getStorageLocationId())
                    .eq(MaterialALLInventoryManagement::getMaterialCode, materialALLInventoryManagementReq.getItemCode())
                    .ge(MaterialALLInventoryManagement::getFrozenQuantity, materialALLInventoryManagementReq.getFrozenQuantity())
                    .last("limit 1"));
            if (materialALLInventoryManagement == null) {
                throw new ServiceException(MaterialStatusCode.NO_MATERIAL_QUALITY.getCode(), MaterialStatusCode.NO_MATERIAL_QUALITY.getMsg());
            }
            if (materialALLInventoryManagement.getAvailableQuantity() == null) {
                if (materialALLInventoryManagement.getStockQuantity() == null) {
                    throw new ServiceException(MaterialStatusCode.NO_USE_QUALITY.getCode(), MaterialStatusCode.NO_USE_QUALITY.getMsg());
                }
            }
            BigDecimal available = materialALLInventoryManagement.getAvailableQuantity().add(materialALLInventoryManagementReq.getFrozenQuantity());
            materialALLInventoryManagement.setAvailableQuantity(available);
            BigDecimal subtract = materialALLInventoryManagement.getFrozenQuantity().subtract(materialALLInventoryManagementReq.getFrozenQuantity());
            materialALLInventoryManagement.setFrozenQuantity(subtract);
            baseMapper.updateById(materialALLInventoryManagement);
        }

    }

    @Override
    public Map<String, String> getExMap() {
        Map<String, String> expMap = new HashMap<>();
        List<MaterialCpBcpItems> matericalGetList = baseMapper.getMatericalGetList();
        for (MaterialCpBcpItems materialCpBcpItems : matericalGetList) {
            expMap.put(materialCpBcpItems.getItemCode(),materialCpBcpItems.getExecutionStandard());
        }
        return expMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = UPDATE_FROZEN_QUANTITY, prefixKey = "lock_", waitTime = 5)
    public void updateFrozenQuantity(List<MaterialALLInventoryManagementReq> materialALLInventoryManagementReqList) {
        for (MaterialALLInventoryManagementReq materialALLInventoryManagementReq : materialALLInventoryManagementReqList) {
            MaterialALLInventoryManagement materialALLInventoryManagement = baseMapper.selectOne(Wrappers.<MaterialALLInventoryManagement>lambdaQuery()
                    .eq(MaterialALLInventoryManagement::getWareHouseCode, MaterialWareHouseCode.YCLK_CK.getMsg())
                    .eq(MaterialALLInventoryManagement::getBatchNumber, materialALLInventoryManagementReq.getBatchNumber())
                    .eq(MaterialALLInventoryManagement::getBarcodeNumber, materialALLInventoryManagementReq.getBarcodeNumber())
                    .eq(MaterialALLInventoryManagement::getStorageLocation, materialALLInventoryManagementReq.getStorageLocationId())
                    .eq(MaterialALLInventoryManagement::getMaterialCode, materialALLInventoryManagementReq.getItemCode()).last("limit 1"));
            if (materialALLInventoryManagement.getAvailableQuantity() == null) {
                if (materialALLInventoryManagement.getStockQuantity() == null) {
                    throw new ServiceException(MaterialStatusCode.NO_USE_QUALITY.getCode(), MaterialStatusCode.NO_USE_QUALITY.getMsg());
                }
                materialALLInventoryManagement.setAvailableQuantity(BigDecimal.valueOf(materialALLInventoryManagement.getStockQuantity()));
            }

            if (materialALLInventoryManagement.getAvailableQuantity().compareTo(materialALLInventoryManagementReq.getFrozenQuantity()) < 0) {
                throw new ServiceException(MaterialStatusCode.USE_QUALITY_LESS_OUT_USE.getCode(), MaterialStatusCode.USE_QUALITY_LESS_OUT_USE.getMsg());
            }
            BigDecimal subtract = materialALLInventoryManagement.getAvailableQuantity().subtract(materialALLInventoryManagementReq.getFrozenQuantity());
            materialALLInventoryManagement.setAvailableQuantity(subtract);
            if (materialALLInventoryManagement.getFrozenQuantity() == null) {
                materialALLInventoryManagement.setFrozenQuantity(materialALLInventoryManagementReq.getFrozenQuantity());
            } else {
                BigDecimal add = materialALLInventoryManagement.getFrozenQuantity().add(materialALLInventoryManagementReq.getFrozenQuantity());
                materialALLInventoryManagement.setFrozenQuantity(add);
            }
            baseMapper.updateById(materialALLInventoryManagement);
        }
    }

    @Override
    public String approveProcess(ApproveProcessReq approveProcessReq) {
        BpmProcessInstanceCreate instanceCreate = new BpmProcessInstanceCreate();
        instanceCreate.setBusinessKey(approveProcessReq.getBusinessKey());
        instanceCreate.setMenuId(approveProcessReq.getMenuId());
        //发起流程
        if (StringUtils.isNotBlank(approveProcessReq.getPreparerId())) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(Constants.PROCESS_INSTANCE_STARTER_USER_ID, approveProcessReq.getPreparerId());
            variables.put(Constants.PROCESS_INSTANCE_BUSINESS_KEY, approveProcessReq.getBusinessKey());
            variables.put(Constants.PROCESS_INSTANCE_MENU_ID, approveProcessReq.getMenuId());
            instanceCreate.setVariables(variables);
        }
        return commonService.startProcess(instanceCreate);
    }

    @Override
    public List<MaterialALLInventoryManagement> getByMaterialCode(List<String> materialCodes) {
        if (CollectionUtils.isNotEmpty(materialCodes)) {
            return lambdaQuery().in(MaterialALLInventoryManagement::getMaterialCode, materialCodes).isNotNull(MaterialALLInventoryManagement::getBatchNumber).list();
        }
        return Collections.emptyList();
    }

    @Override
    public List<String> newPcSelectList() {
        return baseMapper.getNewTPH();
    }

    @Override
    public MaterialALLInventoryManagement getNewPcNumberList(String aTypeCode) {
        MaterialALLInventoryManagement materialALLInventoryManagement = baseMapper.getMaterialALLInventoryManagement(aTypeCode);
        return materialALLInventoryManagement;
    }

    @Override
    public List<MaterialALLInventoryManagement> getMaterialLocationSelectList() {
        return baseMapper.getMaterialLocationSelectList();
    }

    @Override
    public List<MaterialALLInventoryManagement> getMaterialLocationByItemCode(String itemCode) {
        return baseMapper.getMaterialLocationByItemCode(itemCode);
    }


}
